﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Dycox.Drawing;

namespace Dycox.Windows.Forms
{
    public class DiagramPanel : Panel
    {

        public DiagramPanel()
        {
            _shapes = new DiagramShapeCollection();
            _shapes.CollectionChanged += _shapes_CollectionChanged;

            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        }

        void _shapes_CollectionChanged(object sender, EventArgs e)
        {
            this.Invalidate();
        }

        DiagramShapeCollection _shapes;

        public DiagramShapeCollection Shapes
        {
            get { return _shapes; }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            
            DrawLinks(e);
            base.OnPaint(e);
        }

        private void DrawLinks(PaintEventArgs e)
        {
            _shapes.DrawShapes(e.Graphics);
        }

        protected override void OnControlAdded(ControlEventArgs e)
        {
            base.OnControlAdded(e);

            if (_hosts == null)
                _hosts = new Dictionary<Control, DiagramControlHost>();

            DiagramControlHost host = new DiagramControlHost(e.Control);

            _shapes.Add(host);
            _hosts.Add(e.Control, host);
        }

        Dictionary<Control, DiagramControlHost> _hosts;

        protected override void OnControlRemoved(ControlEventArgs e)
        {
            base.OnControlRemoved(e);

            if (_hosts != null)
            {
                Control ctl = e.Control;
                DiagramControlHost host;

                if (_hosts.TryGetValue(ctl, out host))
                    _shapes.Remove(host);
            }

        }

        public ShapeLink LinkControl(Control start, int startPoint, Control end, int endPoint, DiagramLinkLineType type = DiagramLinkLineType.RightAngle)
        {
            if (start == null)
                throw new ArgumentNullException("start");

            if (end == null)
                throw new ArgumentNullException("end");

            if (_hosts != null)
            {
                DiagramControlHost host1, host2;

                if (_hosts.TryGetValue(start, out host1) && _hosts.TryGetValue(end, out host2))
                {
                    return _shapes.AddLink(host1, startPoint, host2, endPoint, type);
                }
            }

            throw new ArgumentException("Either start or end control is not owned by this panel.");
        }

        public DiagramControlHost GetHostingShape(Control control)
        {
            if (control == null)
                throw new ArgumentNullException("control");

            if (_hosts != null)
            {
                DiagramControlHost host;

                if (_hosts.TryGetValue(control, out host))
                    return host;
            }

            return null;
        }
    }

    public class DiagramControlEndPoint : DiagramEndPoint
    {
        public DiagramControlEndPoint(Control control, int hotPointID)
            : base(new DiagramControlHost(control), hotPointID)
        {

        }

        public Control TargetControl
        {
            get
            {
                return ((DiagramControlHost)this.TargetShape).TargetControl;
            }
        }
    }

    //public class DiagramControlLink
    //{
    //    public DiagramControlLink(Control startControl, int startHotPoint, Control endControl, int endHotPoint, DiagramLinkLineType type)
    //        : this(new DiagramControlEndPoint(startControl, startHotPoint), new DiagramControlEndPoint(endControl, endHotPoint), type)
    //    {
    //    }

    //    public DiagramControlLink(DiagramControlEndPoint start, DiagramControlEndPoint end, DiagramLinkLineType type)
    //    {
    //        if (start == null) throw new ArgumentNullException("start");
    //        if (end == null) throw new ArgumentNullException("end");

    //        _start = start;
    //        _end = end;

    //        LineType = type;
    //    }

    //    private DiagramControlEndPoint _start;

    //    public DiagramControlEndPoint Start
    //    {
    //        get { return _start; }
    //    }

    //    private DiagramControlEndPoint _end;

    //    public DiagramControlEndPoint End
    //    {
    //        get { return _end; }
    //    }

    //    private DiagramLinkLineType _lineType;

    //    public DiagramLinkLineType LineType
    //    {
    //        get { return _lineType; }
    //        set
    //        {
    //            if (_lineType != value || _linkLine == null)
    //            {
    //                _lineType = value;
    //                Initialize();
    //            }
    //        }
    //    }

    //    private DiagramLine _linkLine;

    //    public DiagramLine LinkLine
    //    {
    //        get { return _linkLine; }
    //    }

    //    private void Initialize()
    //    {
    //        DiagramLine line;
            
    //        switch (_lineType)
    //        {
    //            case DiagramLinkLineType.Straight:
    //                line = DiagramStraightLine.CreateLink(Start.TargetShape, Start.HotPointID, _end.TargetShape, _end.HotPointID);
    //                break;
    //            case DiagramLinkLineType.RightAngle:
    //                line = CreatePolyline();
    //                break;
    //            case DiagramLinkLineType.Bezier:
    //                throw new NotImplementedException();
    //            default:
    //                throw new InvalidOperationException("Line type" + _lineType + " is not valid.");
    //        }

    //        if (_linkLine != null)
    //        {
    //            PropertyDescriptorCollection coll0, coll1;

    //            coll0 = TypeDescriptor.GetProperties(_linkLine);
    //            coll1 = TypeDescriptor.GetProperties(line);

    //            foreach (PropertyDescriptor p0 in coll0)
    //            {
    //                PropertyDescriptor p1 = coll1[p0.Name];
    //                if (p1 != null && p1.PropertyType.IsAssignableFrom(p0.PropertyType))
    //                    p1.SetValue(line, p0.GetValue(_linkLine));
    //            }
    //        }

    //        _linkLine = line;


    //    }

    //    private DiagramPolyline CreatePolyline()
    //    {
    //        PointF pt1 = _start.Location, pt2 = _end.Location;
    //        float x = pt2.X - pt1.X, y = pt2.Y - pt1.Y;
    //        int hpid2 = _end.HotPointID, hpid1 = _start.HotPointID;
    //        Direction dir;
    //        float turnning = 1f;

    //        if (hpid1 >= 6 && hpid1 <= 9 || hpid1 >= 14)
    //        {
    //            if (x >= 0) dir = Direction.East;
    //            else dir = Direction.West;

    //            if (hpid2 >= 6 && hpid2 <= 9 || hpid2 >= 14)
    //                turnning = .5f;
    //        }
    //        else
    //        {
    //            if (y >= 0) dir = Direction.South;
    //            else dir = Direction.North;

    //            if (hpid2 >= 1 && hpid2 <= 5 || hpid2 >= 10 && hpid2 <= 13)
    //                turnning = .5f;
    //        }

    //        return DiagramPolyline.CreateLink(_start.TargetShape, _start.HotPointID, _end.TargetShape, _end.HotPointID, dir, turnning);
    //    }

    //}

    //public class DiagramControlLinkCollection : Collection<DiagramControlLink>
    //{
    //    public DiagramControlLinkCollection()
    //    {

    //    }

    //    public DiagramControlLink Add(Control startControl, int startHotPoint, Control endControl, int endHotPoint, DiagramLinkLineType type)
    //    {
    //        return Add(startControl, startHotPoint, endControl, endHotPoint, type, null);
    //    }

    //    public DiagramControlLink Add(Control startControl, int startHotPoint, Control endControl, int endHotPoint, DiagramLinkLineType type, string text)
    //    {
    //        DiagramControlLink link = new DiagramControlLink(startControl, startHotPoint, endControl, endHotPoint, type);
    //        link.LinkLine.Text = text;
            
    //        this.Add(link);

    //        return link;
    //    }
    //}
}
